package top.huntwolf.admin.filter;

import com.alibaba.fastjson.JSON;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import top.huntwolf.admin.common.JsonResult;
import top.huntwolf.admin.common.enums.CodeMsg;
import top.huntwolf.admin.exception.ServiceException;
import top.huntwolf.admin.pojo.JwtToken;
import top.huntwolf.admin.pojo.shop.ShopContext;
import top.huntwolf.admin.utils.TokenUtil;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;



/**
 * 过滤器 在登陆完成后 拦截需要处理的接口
 */
@Component
public class JWTFilter extends BasicHttpAuthenticationFilter {


    /**
     * 解决跨域
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
        // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态'
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return true;
        }
        return super.preHandle(request, response);
    }

    /**
     * 过滤器拦截请求的入口方法
     * 返回 true 则允许访问
     * 返回false 则禁止访问，会进入 onAccessDenied()
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        boolean allowed = false;

        try {
            allowed =  executeLogin(request,response);
        } catch (Exception e) {
            //这里只抓 out方法产生的IO异常
            e.printStackTrace();
        }

        return allowed || super.isPermissive(mappedValue);
    }

    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        try {
            AuthenticationToken token = createToken(request, response);

            //会进入JwtRealm解析token是否有效
            getSubject(request, response).login(token);
            return true;

        }catch (Exception e){
            Throwable cause = e.getCause();

            if (cause instanceof  AuthenticationException) {
                //login 校验失败
                out(response,JsonResult.error(CodeMsg.SESSION_ERROR));
                return false;
            }
            else if (cause instanceof NullPointerException) {
                //无携带token 抛出空指针异常
                out(response,JsonResult.error(CodeMsg.TOKEN_NOT_EXIST));
                return false;
            }
            else {
                out(response,JsonResult.error(CodeMsg.SESSION_ERROR));
                return false;
            }
        }
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
//        HttpServletResponse httpResponse = WebUtils.toHttp(response);
//        String content = JSON.toJSONString(JsonResult.error(CodeMsg.SESSION_ERROR));
//        httpResponse.setContentType("application/json;charset=UTF-8");
//        httpResponse.getWriter().println(content);
        return false;
    }

    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) {
        String token = TokenUtil.getRequest().getHeader("token");
        JwtToken jwtToken = new JwtToken(token);
        return jwtToken;
    }


    //全局异常处理无法处理过滤器中的异常，所以采用直接返回数据到浏览器
    private void out(ServletResponse response,JsonResult<Object> res) throws IOException {
        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
        String msg = JSON.toJSONString(res);
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json; charset=utf-8");
        httpServletResponse.getOutputStream().write(msg.getBytes());
    }

    @Override
    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
        ShopContext.remove();
    }
}
